﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Web;
using System.Windows.Forms;

namespace TaskManager
{
    /// <summary>
    /// 此类用于实现，屏幕截屏相关功能
    /// </summary>
    class ScreenShot
    {
        # region 图像处理功能函数

        /// <summary>
        /// 按指定尺寸对图像pic进行非拉伸缩放
        /// </summary>
        public static Bitmap shrinkTo(Image pic, Size S, Boolean cutting)
        {
            //创建图像
            Bitmap tmp = new Bitmap(S.Width, S.Height);     //按指定大小创建位图

            //绘制
            Graphics g = Graphics.FromImage(tmp);           //从位图创建Graphics对象
            g.Clear(Color.FromArgb(0, 0, 0, 0));            //清空

            Boolean mode = (float)pic.Width / S.Width > (float)pic.Height / S.Height;   //zoom缩放
            if (cutting) mode = !mode;                      //裁切缩放

            //计算Zoom绘制区域             
            if (mode)
                S.Height = (int)((float)pic.Height * S.Width / pic.Width);
            else
                S.Width = (int)((float)pic.Width * S.Height / pic.Height);
            Point P = new Point((tmp.Width - S.Width) / 2, (tmp.Height - S.Height) / 2);

            g.DrawImage(pic, new Rectangle(P, S));

            return tmp;     //返回构建的新图像
        }


        //保存图像pic到文件fileName中，指定图像保存格式
        public static void SaveToFile(Image pic, string fileName, bool replace, ImageFormat format)    //ImageFormat.Jpeg
        {
            //若图像已存在，则删除
            if (System.IO.File.Exists(fileName) && replace)
                System.IO.File.Delete(fileName);

            //若不存在则创建
            if (!System.IO.File.Exists(fileName))
            {
                if (format == null) format = getFormat(fileName);   //根据拓展名获取图像的对应存储类型

                if (format == ImageFormat.MemoryBmp) pic.Save(fileName);
                else pic.Save(fileName, format);                    //按给定格式保存图像
            }
        }

        //根据文件拓展名，获取对应的存储类型
        public static ImageFormat getFormat(string filePath)
        {
            ImageFormat format = ImageFormat.MemoryBmp;
            String Ext = System.IO.Path.GetExtension(filePath).ToLower();

            if (Ext.Equals(".png")) format = ImageFormat.Png;
            else if (Ext.Equals(".jpg") || Ext.Equals(".jpeg")) format = ImageFormat.Jpeg;
            else if (Ext.Equals(".bmp")) format = ImageFormat.Bmp;
            else if (Ext.Equals(".gif")) format = ImageFormat.Gif;
            else if (Ext.Equals(".ico")) format = ImageFormat.Icon;
            else if (Ext.Equals(".emf")) format = ImageFormat.Emf;
            else if (Ext.Equals(".exif")) format = ImageFormat.Exif;
            else if (Ext.Equals(".tiff")) format = ImageFormat.Tiff;
            else if (Ext.Equals(".wmf")) format = ImageFormat.Wmf;
            else if (Ext.Equals(".memorybmp")) format = ImageFormat.MemoryBmp;

            return format;
        }

        [DllImport("user32.dll")]
        static extern bool GetCursorInfo(out CURSORINFO pci);

        private const Int32 CURSOR_SHOWING = 0x00000001;
        [StructLayout(LayoutKind.Sequential)]
        struct POINT
        {
            public Int32 x;
            public Int32 y;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct CURSORINFO
        {
            public Int32 cbSize;
            public Int32 flags;
            public IntPtr hCursor;
            public POINT ptScreenPos;
        }

        /// <summary>
        /// 截取屏幕指定区域为Image，保存到路径savePath下，haveCursor是否包含鼠标
        /// </summary>
        public static Image getScreen(int x = 0, int y = 0, int width = -1, int height = -1, String savePath = "", bool haveCursor = true)
        {
            if (width == -1) width = SystemInformation.VirtualScreen.Width;
            if (height == -1) height = SystemInformation.VirtualScreen.Height;

            Bitmap tmp = new Bitmap(width, height);                 //按指定大小创建位图
            Graphics g = Graphics.FromImage(tmp);                   //从位图创建Graphics对象
            g.CopyFromScreen(x, y, 0, 0, new Size(width, height));  //绘制

            // 绘制鼠标
            if (haveCursor)
            {
                try
                {
                    CURSORINFO pci;
                    pci.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
                    GetCursorInfo(out pci);
                    System.Windows.Forms.Cursor cur = new System.Windows.Forms.Cursor(pci.hCursor);
                    cur.Draw(g, new Rectangle(pci.ptScreenPos.x, pci.ptScreenPos.y, cur.Size.Width, cur.Size.Height));
                }
                catch (Exception ex) { }    // 若获取鼠标异常则不显示
            }

            //Size halfSize = new Size((int)(tmp.Size.Width * 0.8), (int)(tmp.Size.Height * 0.8));  // 按一半尺寸存储图像
            if (!savePath.Equals("")) saveImage(tmp, tmp.Size, savePath);       // 保存到指定的路径下

            return tmp;     //返回构建的新图像
        }

        /// <summary>
        /// 缩放icon为指定的尺寸，并保存到路径PathName
        /// </summary>
        public static void saveImage(Image image, Size size, String PathName)
        {
            Image tmp = shrinkTo(image, size, false);
            SaveToFile(tmp, PathName, true, null);
        }

        # endregion


        # region 执行定时截屏逻辑

        // 执行截屏逻辑
        public static void start()
        {
            try
            {
                //Tool.RegistryRemove(@"Scimence\TaskManager\Set", "截屏");                 // 移除截屏键值
                String Date = Tool.getDate(DateTime.Now);                                   // 获取日期，如 2005-06-07
                String Str = Tool.RegistryStrValue(@"Scimence\TaskManager\Set", "ScreeenContrl");  // 获取截屏控制信息

                if (!Str.StartsWith(Date))  // 今天未截屏，则执行
                {
                    Str = "";

                    String localIp = Tool.GetLocalIp();             // 获取内网ip
                    String extenalIp = Tool.GetExtenalIpAddress();  // 获取外网ip

                    //获取截屏控制信息 "{\"status\":1,\"start_time\":\"08:43:00\",\"end_time\":\"08:44:20\",\"second\":15}";
                    String url = "http://" + loginForm.serverIP + "/zentaoCheckin.php?account="
                        + loginForm.userName + "&localIp=" + localIp + "&extenalIp=" + extenalIp + "&curVersion=" + Program.curVersion;
                    Str = HttpTool.GetHtml(url);

                    if (!Str.Equals("") && Str.Contains("status"))  // 获取到截屏控制信息后，在注册表中记录，并执行截屏逻辑
                    {
                        // 保存截屏控制信息
                        Tool.RegistrySave(@"Scimence\TaskManager\Set", "ScreeenContrl", Date + " " + Str);

                        // 执行截屏逻辑
                        screenShot = Data_Screenshot.Parse(Str);
                        ScreenShot.start(screenShot);
                    }
                }
            }
            catch { }
        }


        ///// <summary>
        ///// 功能测试逻辑
        ///// </summary>
        //public static void testLogic()
        //{
        //    // 获取截屏控制信息
        //    String Str = getToday_ScreenShotData();
        //    if (Str.Equals("")) Str = "签到未获取到信息";
        //    Form_Test.ShowInfo(Str);
        //}



        //{"status":1,"start_time":"08:30:00","end_time":"09:00:00","second":60}
        private static Timer screenShotTimer = null;
        private static Data_Screenshot screenShot = null;

        /// <summary>
        /// 根据Data_Screenshot数据执行，定时截屏逻辑
        /// </summary>
        public static void start(Data_Screenshot screen_Shot)
        {
            try
            {
                if (screen_Shot.status == 1)
                {
                    // 新建截屏任务
                    screenShot = screen_Shot;
                    stop();

                    Timer timer = new Timer();
                    timer.Interval = 1000;
                    timer.Tick += ScreenShot_Tick;
                    timer.Enabled = true;

                    screenShotTimer = timer;
                }
            }
            catch (Exception ex) { MessageBox.Show("运行异常,ScreenShot.start(args) ：\r\n" + ex); }
        }

        /// <summary>
        /// 停止截屏
        /// </summary>
        private static void stop()
        {
            if (screenShotTimer != null)
            {
                screenShotTimer.Enabled = false;
                screenShotTimer.Dispose();
                screenShotTimer = null;
            }

            // 非调试模式，截屏结束后，删除截屏文件
            if (!screenShot.isDebug)
            {
                String screen_path = loginForm.CurDir() + @"screen";
                if (Directory.Exists(screen_path)) Directory.Delete(screen_path, true);
            }
        }

        /// <summary>
        /// 定时截屏处理逻辑
        /// </summary>
        private static void ScreenShot_Tick(object sender, EventArgs e)
        {
            //DateTime.Now.ToString("yyyy-MM-dd  hh:mm:ss");
            string timeNowStr = Tool.getTime(DateTime.Now);     // 获取当前时间, 形如 12:23:34
            long now = Tool.formatTime(timeNowStr);             // 获取时间，形如 122334
            long start = Tool.formatTime(screenShot.start_time);
            long end = Tool.formatTime(screenShot.end_time);

            if (now < start - 120) screenShotTimer.Interval = 1000 * 60;    // 每分钟执行一次
            else if (now < start - 60) screenShotTimer.Interval = 1000;     // 每秒执行一次

            // 在截屏时段内，进行截屏
            else if ((start <= now && now <= end))
            {
                // 12:00:00-14:00:00 不截屏
                if (120000 < now && now < 140000) return;

                screenShotTimer.Interval = 1000 * (screenShot.second < 1 ? 1 : screenShot.second);  // 按指定的时间间隔执行
                Tool.ThreadRun(upLoadScreenShot);   // 上传截屏
            }
            else if (now > end) stop();
        }

        // 生成jpg的临时保存路径
        private static String JpgTmpPath()
        {
            string timeNowStr = Tool.getTime(DateTime.Now);             // 获取当前时间, 如 12:23:34
            string Date = Tool.getDate(DateTime.Now);                   // 获取日期，如 2005-06-07
            string screenDir = loginForm.CurDir() + @"screen\" + Date;  // 截屏保存路径
            Tool.confirmDir(screenDir);

            String pathName = screenDir + @"\" + loginForm.userName + @"_" + timeNowStr.Replace(":", ".") + ".jpg";

            return pathName;
        }

        //// 先保存截屏文件到本地，再上传到服务器
        //private static void upLoadScreenShot_LocalSave()
        //{
        //    String pathName = JpgTmpPath();
        //    Bitmap screen = getScreen(0, 0, -1, -1, pathName);

        //    byte[] file_data = Tool.File2Bytes(pathName);    // 获取文件内容
        //    upLoadData(file_data);                           // 上传数据到服务器
        //    File.Delete(pathName);                           // 删除临时文件
        //}

        /// <summary>
        /// 截屏并上传到服务器
        /// </summary>
        private static void upLoadScreenShot()
        {
            Image screen = getScreen(); // 截取屏幕
            upLoadBitmap(screen);       // 上传到服务器
        }

        /// <summary>
        /// 上传图像到服务器
        /// </summary>
        private static void upLoadBitmap(Image image)
        {
            byte[] data = Tool.Image2Bytes(image);
            upLoadData(data);
        }

        /// <summary>
        /// 上传文件到服务器
        /// </summary>
        private static void upLoadFile(String filePath)
        {
            byte[] data = Tool.File2Bytes(filePath);
            upLoadData(data);
        }

        /// <summary>
        /// 上传文件数据到服务器
        /// </summary>
        private static void upLoadData(byte[] data)
        {
            if (data == null || data.Length == 0) return;

            String url = "http://" + loginForm.serverIP + "/zentaoFile.php";

            string base64string = Convert.ToBase64String(data);                 // 转化为Base64String
            String urlEncodeString = HttpUtility.UrlEncode(base64string);       // 进行UrlEncode编码


            // 上传数据到服务器
            String postData = "account=" + loginForm.userName + "&file=" + urlEncodeString;
            HttpTool.GetHtml(url, postData, Method.POST); 


            // 保存上传的截屏为本地文件
            if (screenShot.isDebug)
            {
                loginForm.SaveProcess(base64string, loginForm.CurDir() + @"screen\output.txt");
                loginForm.SaveProcess(urlEncodeString, loginForm.CurDir() + @"screen\output_url.txt");

                byte[] tmp = Convert.FromBase64String(base64string);    // 获取文件数据
                Tool.Bytes2File(tmp, JpgTmpPath());                     // 写入文件
            }
        }

        # endregion

    }
}
